import base64
import os
import re
import binascii


def asn1parse(der_data, indent=0, offset=0):
    """
    实现类似 OpenSSL asn1parse 的功能

    参数:
    der_data: DER格式的二进制数据
    indent: 缩进级别
    offset: 当前偏移量

    返回:
    处理后的字节数
    """
    if not der_data:
        return 0

    # 解析标签字节
    tag_byte = der_data[0]
    tag_class = (tag_byte >> 6) & 0x03
    tag_pc = (tag_byte >> 5) & 0x01
    tag_number = tag_byte & 0x1F

    # 处理长标签
    length_offset = 1  # 初始偏移量为1（标签字节）

    if tag_number == 0x1F:
        # 长标签处理
        tag_number = 0
        i = 1
        while i < len(der_data):
            tag_number = (tag_number << 7) | (der_data[i] & 0x7F)
            length_offset += 1  # 增加偏移量
            if not (der_data[i] & 0x80):
                break
            i += 1

    # 解析长度字节
    if length_offset >= len(der_data):
        print(f"{'  ' * indent}位置 {offset}: 数据不足，无法解析长度")
        return length_offset

    length_byte = der_data[length_offset]

    # 短格式长度 (1字节)
    if length_byte < 0x80:
        length = length_byte
        value_offset = length_offset + 1
        header_length = value_offset  # 标签字节 + 1字节长度
    else:
        # 长格式长度
        length_bytes = length_byte & 0x7F
        if length_offset + 1 + length_bytes > len(der_data):
            print(f"{'  ' * indent}位置 {offset}: 数据不足，无法解析长格式长度")
            return length_offset + 1

        length = 0
        for i in range(length_bytes):
            length = (length << 8) | der_data[length_offset + 1 + i]
        value_offset = length_offset + 1 + length_bytes
        header_length = value_offset  # 标签字节 + 长度字节数 + 1（长度指示字节）

    # 检查数据是否足够
    if value_offset + length > len(der_data):
        print(f"{'  ' * indent}位置 {offset}: 数据不足，需要 {length} 字节，但只有 {len(der_data) - value_offset} 字节")
        return len(der_data)

    # 获取值部分
    value_data = der_data[value_offset:value_offset + length]

    # 打印 ASN.1 结构信息
    tag_class_str = {
        0: "Universal",
        1: "Application",
        2: "Context-specific",
        3: "Private"
    }.get(tag_class, f"Unknown({tag_class})")

    tag_pc_str = "Constructed" if tag_pc else "Primitive"

    # 尝试获取标签名称
    tag_name = get_tag_name(tag_class, tag_number)

    # 打印结构信息，使用正确的头部长度
    print(
        f"{'  ' * indent}位置 {offset}: d={indent} hl={header_length} l={length:3d} cons={tag_pc_str} {tag_class_str} {tag_name}")

    # 打印十六进制数据（如果长度不超过32字节）
    if length <= 32:
        hex_str = binascii.hexlify(value_data).decode('ascii')
        print(f"{'  ' * indent}    0000 - {hex_str}")
    elif length > 0:
        hex_str1 = binascii.hexlify(value_data[:16]).decode('ascii')
        hex_str2 = binascii.hexlify(value_data[16:32]).decode('ascii') if length > 16 else ""
        print(f"{'  ' * indent}    0000 - {hex_str1}")
        if hex_str2:
            print(f"{'  ' * indent}    0010 - {hex_str2}")
        print(f"{'  ' * indent}    [剩余 {length - 32} 字节未显示]")

    # 如果是构造类型，递归解析
    if tag_pc:
        pos = 0
        while pos < length:
            processed = asn1parse(value_data[pos:], indent + 1, offset + value_offset + pos)
            pos += processed

    # 返回处理的总字节数
    return value_offset + length


def get_tag_name(tag_class, tag_number):
    """
    获取标签名称

    参数:
    tag_class: 标签类别
    tag_number: 标签编号

    返回:
    标签名称
    """
    # 通用标签名称
    if tag_class == 0:  # Universal
        tag_names = {
            0: "EOC",
            1: "BOOLEAN",
            2: "INTEGER",
            3: "BIT STRING",
            4: "OCTET STRING",
            5: "NULL",
            6: "OBJECT IDENTIFIER",
            7: "Object Descriptor",
            8: "EXTERNAL",
            9: "REAL",
            10: "ENUMERATED",
            11: "EMBEDDED PDV",
            12: "UTF8String",
            16: "SEQUENCE",
            17: "SET",
            18: "NumericString",
            19: "PrintableString",
            20: "TeletexString",
            21: "VideotexString",
            22: "IA5String",
            23: "UTCTime",
            24: "GeneralizedTime",
            25: "GraphicString",
            26: "VisibleString",
            27: "GeneralString",
            28: "UniversalString",
            30: "BMPString"
        }
        return tag_names.get(tag_number, f"Tag({tag_number})")

    # 应用标签
    elif tag_class == 1:  # Application
        return f"[APPLICATION {tag_number}]"

    # 上下文特定标签
    elif tag_class == 2:  # Context-specific
        return f"[CONTEXT {tag_number}]"

    # 私有标签
    elif tag_class == 3:  # Private
        return f"[PRIVATE {tag_number}]"

    # 未知标签
    else:
        return f"Tag({tag_class},{tag_number})"